package com.xiejun.netty;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Scanner;
import java.util.Set;

public class SimpleNettyClient {
    
    private final String host;
    private final int port;
    private Selector selector;
    private SocketChannel socketChannel;
    
    public SimpleNettyClient(String host, int port) {
        this.host = host;
        this.port = port;
    }
    
    public void start() throws IOException {
        // 打开选择器
        selector = Selector.open();
        
        // 打开套接字通道
        socketChannel = SocketChannel.open();
        socketChannel.configureBlocking(false);
        
        // 连接到服务器
        boolean connected = socketChannel.connect(new InetSocketAddress(host, port));
        
        if (connected) {
            socketChannel.register(selector, SelectionKey.OP_READ);
        } else {
            socketChannel.register(selector, SelectionKey.OP_CONNECT);
        }
        
        System.out.println("Simple Netty Client started and connecting to " + host + ":" + port);
        
        // 启动用户输入线程
        startInputThread();
        
        // 事件循环
        while (true) {
            selector.select();
            
            Set<SelectionKey> selectedKeys = selector.selectedKeys();
            Iterator<SelectionKey> keyIterator = selectedKeys.iterator();
            
            while (keyIterator.hasNext()) {
                SelectionKey key = keyIterator.next();
                
                if (key.isConnectable()) {
                    handleConnect(key);
                } else if (key.isReadable()) {
                    handleRead(key);
                }
                
                keyIterator.remove();
            }
        }
    }
    
    private void startInputThread() {
        Thread inputThread = new Thread(new Runnable() {
            @Override
            public void run() {
                Scanner scanner = new Scanner(System.in);
                try {
                    while (true) {
                        System.out.print("Enter message (or 'quit' to exit): ");
                        String message = scanner.nextLine();
                        if ("quit".equalsIgnoreCase(message)) {
                            socketChannel.close();
                            System.exit(0);
                        }
                        
                        if (socketChannel.isConnected()) {
                            ByteBuffer buffer = ByteBuffer.wrap(message.getBytes());
                            socketChannel.write(buffer);
                        }
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        });
        
        inputThread.setDaemon(true);
        inputThread.start();
    }
    
    private void handleConnect(SelectionKey key) throws IOException {
        SocketChannel channel = (SocketChannel) key.channel();
        
        if (channel.isConnectionPending()) {
            channel.finishConnect();
        }
        
        channel.register(selector, SelectionKey.OP_READ);
        System.out.println("Connected to server");
    }
    
    private void handleRead(SelectionKey key) throws IOException {
        SocketChannel channel = (SocketChannel) key.channel();
        ByteBuffer buffer = ByteBuffer.allocate(1024);
        
        int bytesRead = channel.read(buffer);
        if (bytesRead == -1) {
            System.out.println("Server closed the connection");
            channel.close();
            return;
        }
        
        buffer.flip();
        byte[] data = new byte[buffer.remaining()];
        buffer.get(data);
        String message = new String(data);
        
        System.out.println("Received from server: " + message);
    }
    
    public static void main(String[] args) {
        try {
            new SimpleNettyClient("localhost", 8080).start();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}